#ifndef _SCHEDULER_H_
#define _SCHEDULER_H_

#include "fiber.h"
#include "thread.h"

#include <mutex>
#include <vector>

namespace zsylar {

class Scheduler
{
public:
    // 构造函数
    // threads: 线程池的线程数量
    // use_caller: 是否使用调用者线程作为调度器线程
    // name: 调度器的名称
    Scheduler(size_t threads = 1, bool use_caller = true, 
            const std::string& name="Scheduler");
    // 析构函数-释放调度器资源
    virtual ~Scheduler();

    const std::string& getName() const { return m_name; }

public:
    // 获取正在运行的调度器
    static Scheduler* GetThis();

protected:
    // 设置正在运行的调度器
    void SetThis();

public:
    // 添加任务到任务队列，template 是C++中的关键字，用于声明模板。
    template <class FiberOrCb>
    // 如果任务是协程或回调函数，则将其添加到任务队列中
    // thread: 指定任务需要运行的线程id，默认为-1表示不指定线程
    // 如果任务队列为空，则唤醒调度器   
    void scheduleLock(FiberOrCb fc, int thread = -1)
    {
        bool need_tickle;
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            // 如果任务队列为空，则需要唤醒调度器
            need_tickle = m_tasks.empty();
            
            ScheduleTask task(fc, thread);
            // 如果任务是协程或回调函数，则将其添加到任务队列中
            if (task.fiber || task.cb) 
            {
                m_tasks.push_back(task);
            }
        }

        if (need_tickle)
        {
            tickle(); // 唤醒调度器
        }
    }

    // 启动线程池
    virtual void start();
    // 关闭线程池
    virtual void stop();

protected:
    // 唤醒调度器
    virtual void tickle();
    // 线程函数
    virtual void run(); 
    // 空闲协程函数
    virtual void idle();
    // 是否可以关闭调度器
    virtual bool stopping();
    
    bool hasIdleThread()
    {
        return m_idleThreadCount > 0; // 检查是否有空闲线程
    }

private:
    // 任务
    struct ScheduleTask
    {
        std::shared_ptr<Fiber> fiber; // 协程
        std::function<void()> cb; // 回调函数
        int thread; // 指定任务需要运行的线程id

        ScheduleTask() 
        {
            fiber = nullptr; // 初始化协程为空
            cb = nullptr; // 初始化回调函数为空
            thread = -1; // 默认线程id为-1，表示不指定线程
        }
		// 构造函数：协程指针 + 线程 ID
        ScheduleTask(std::shared_ptr<Fiber> f, int thr)
        {
            fiber = f; // 设置协程
            thread = thr; // 设置线程id
        }
        // 构造函数：协程指针的引用 + 线程 ID
        ScheduleTask(std::shared_ptr<Fiber>* f, int thr)
        {
            fiber.swap(*f); // 交换协程指针
            thread = thr; // 设置线程id
        }
        // 构造函数：回调函数 + 线程 ID
        ScheduleTask(std::function<void()> f, int thr)
        {
            cb = f; // 设置回调函数
            thread = thr; // 设置线程id
        }
        // 构造函数：回调函数的引用 + 线程 ID
        ScheduleTask(std::function<void()>* f, int thr)
        {
            cb.swap(*f); // 交换回调函数
            thread = thr; // 设置线程id
        }
        // 重置任务
        // 将协程、回调函数和线程id重置为空或默认值
        // 这通常在任务完成后调用，以便重用任务对象
        // 例如，在任务执行完毕后，可以调用 reset() 来清理任务对象
        // 以便下次可以重新使用该任务对象而不需要重新分配
        // 这有助于减少内存分配和释放的开销，提高性能
        void reset()
        {
            fiber = nullptr; // 重置协程为空
            cb = nullptr; // 重置回调函数为空
            thread = -1; // 重置线程id为-1，表示不指定线程
        }
    };

private:
    std::string m_name; // 调度器名称
    std::mutex m_mutex; // 互斥锁，保护任务队列
    std::vector<std::shared_ptr<Thread>> m_threads; // 线程池
    std::vector<ScheduleTask> m_tasks; // 任务队列
    std::vector<int> m_threadIds; // 存储工作线程的线程id
    size_t m_threadCount = 0; // 需要额外创建的线程数
    std::atomic<size_t> m_activeThreadCount = {0}; // 活跃线程数
    std::atomic<size_t> m_idleThreadCount = {0}; // 空闲线程数

    bool m_useCaller; // 主线程是否用作工作线程
    std::shared_ptr<Fiber> m_schedulerFiber; // 调度协程 
    int m_rootThread = -1;  // 主线程的线程id
    bool m_stopping = false; // 是否正在停止调度器
};

}

#endif // _SCHEDULER_H_